Option Explicit

' ======================================================================
' Field
' ======================================================================

' 当前的百分比
Private percent As Double

' Form 中，1% 需要向前移动的距离
Private everyPercentSize As Double

' 当前最高水位线（当前能够到达的最大百分比）
Private highWaterMark As Integer
' 新水线 - 旧水线 的这段距离作为 100% 时，每 1% 对应的多少
Private discountRate As Double
' 上一次的水位线
Private lastHighWaterMark As Integer

' 在当前的水位线标准中，需要前进的数值被拆成 part 个部分
' 每次设置新的水位线时，将会重置为 1
Private part As Integer
' 当前的 part 编号
Private currentPartNo As Integer
' 当前所有 part 中，已经推进完成的那部分的距离
Private refreshedPartPercent As Double

' ==================================================
' 消息标题属性
' ==================================================
' 当前水位线对应的标题
Private highWaterMarkTitle As String
' 当前 part 的标题，每次切换到下一个 part 时都会清空
Private partTitle As String
' Form 中显示的消息的标题 = highWaterMarkTitle + partTitle
Private msgTitle As String


' ======================================================================
' Constructor
' ======================================================================
Private Sub Class_Initialize()
    everyPercentSize = MyProgressBar.lblBack.Width / 100
    percent = 0
    highWaterMark = -1
    lastHighWaterMark = -1

    MyProgressBar.Show 0

    refresh 0, "loading...."
End Sub

Private Sub Class_Terminate()
    Unload MyProgressBar
End Sub

' ======================================================================
' Method
' ======================================================================
' 设置高水位线。只能向上设置，不能回退
' 设置完成后，将进度条推进到上一个高水位线
' @param val 新水位线的值。只能设置为整数值
' @param title 当前水位线的标题
Public Sub setHighWaterMark(ByRef val As Integer, ByRef title As String)
    ' 如果向下设置水线，则忽略这次设置操作
    If val < highWaterMark Then
        Exit Sub
    End If

    If highWaterMark <> -1 Then
        lastHighWaterMark = highWaterMark
    Else
        lastHighWaterMark = 0
    End If

    part = 1
    currentPartNo = 1
    refreshedPartPercent = 0

    ' 计算两个水线之间的距离
    ' 并计算这段距离作为 100% 时，每 1% 对应的多少
    highWaterMark = val
    discountRate = (highWaterMark - lastHighWaterMark) / 100

    ' ==============================
    ' 设置标题
    ' ==============================
    ' 保存当前水线对应的标题
    highWaterMarkTitle = title
    ' 清除 part 标题
    partTitle = ""
    ' 重建消息标题
    createMsgTitle

    refresh 0, ""
End Sub

' 将当前的需要推进的部分拆分成 val 分
' @param val 待推进的部分需要拆分的分数
Public Sub splitPart(ByRef val As Integer)
    part = val
    currentPartNo = 1
    discountRate = (highWaterMark - lastHighWaterMark) / 100 / part
    refreshedPartPercent = 0
End Sub

' 设置当前 part 的标题
' @param title 当前 part 的标题
Public Sub setPartTitle(ByRef title As String)
    ' ==============================
    ' 设置标题
    ' ==============================
    ' 清除 part 标题
    partTitle = title
    ' 重建消息标题
    createMsgTitle
End Sub

' 移动到下一个 part
Public Sub nextPart()
    ' 如果已经移动到了最大 part，则忽略这次操作
    If currentPartNo < part Then
        refreshPercent 100

        refreshedPartPercent = (highWaterMark - lastHighWaterMark) / part * currentPartNo

        currentPartNo = currentPartNo + 1

        ' ==============================
        ' 设置标题
        ' ==============================
        ' 清除 part 标题
        partTitle = ""
        ' 重建消息标题
        createMsgTitle
    End If
End Sub

' 刷新百分比
' 每次刷新都应该按照 100% 为基准设置，方法内部会自动按照水线 + part 来计算实际的百分比
' @param v 百分比数值
Public Sub refreshPercent(ByRef v As Double)
    If highWaterMark = -1 Then
        percent = v + refreshedPartPercent
    Else
        percent = lastHighWaterMark + v * discountRate + refreshedPartPercent
    End If

    MyProgressBar.lblprogress.Width = everyPercentSize * percent
    MyProgressBar.percent = Format(percent, "0.00") & "%"

    MyProgressBar.Repaint
End Sub

' 结束进度条的推进，显示为 100%
Public Sub refreshEnd()
    ' ==============================
    ' 设置百分比
    ' ==============================
    percent = 100
    highWaterMark = -1

    ' ==============================
    ' 设置标题
    ' ==============================
    ' 清除水线的标题
    highWaterMarkTitle = ""
    ' 清除 part 标题
    partTitle = ""
    ' 重建消息标题
    createMsgTitle

    ' ==============================
    ' 刷新 Form 显示
    ' ==============================
    MyProgressBar.lblprogress.Width = everyPercentSize * percent
    MyProgressBar.percent = Format(percent, "0.00") & "%"
    MyProgressBar.msg = "end"

    MyProgressBar.Repaint
End Sub

' 只刷新 Form 上的显示信息
Public Sub refreshMsg(ByRef msg As String)
    MyProgressBar.msg = msgTitle & Chr(10) & Chr(10) & msg
    MyProgressBar.Repaint
End Sub

' 刷新 Form 上显示的 百分比 + 显示信息
Public Sub refresh(ByRef v As Double, ByRef msg As String)
    If highWaterMark = -1 Then
        percent = v + refreshedPartPercent
    Else
        percent = lastHighWaterMark + v * discountRate + refreshedPartPercent
    End If

    MyProgressBar.lblprogress.Width = everyPercentSize * percent
    MyProgressBar.percent = Format(percent, "0.00") & "%"
    MyProgressBar.msg = msgTitle & Chr(10) & Chr(10) & msg

    MyProgressBar.Repaint
End Sub

' ======================================================================
' Private Method
' ======================================================================
' 创建消息标题
Private Sub createMsgTitle()
    ' 只保留 highWaterMarkTitle + msgTitle 中的非空字符串
    ' 如果两个字符串都是空字符串，则将 msgTitle 设置为空字符串
    If highWaterMarkTitle <> "" Then
        msgTitle = highWaterMarkTitle

        If partTitle <> "" Then
            msgTitle = msgTitle & Chr(10) & partTitle
        End If
    ElseIf partTitle <> "" Then
        msgTitle = partTitle
    Else
        msgTitle = ""
    End If
End Sub